<template>
  <div class="editor-container">
    <!-- 标题 -->
    <el-row class="editor-top">
      <el-input
        v-model="article.title"
        type="text"
        placeholder="请输入文章标题"
        maxlength="100"
        show-word-limit
      >
        <template slot="prepend">标题</template>
      </el-input>
    </el-row>
    <!-- 编辑器 -->
    <mavon-editor
      class="editor"
      v-model="article.content"
      boxShadowStyle="none"
      toolbarsBackground="#F5F7FA"
      ref="md"
      :tabSize="4"
      :codeStyle="codeStyles[currentStyle]"
      @imgAdd="handleImgAdd"
      @save="handleSave"
    >
      <template slot="left-toolbar-before">
        <!-- 更换代码样式按钮 -->
        <div
          type="button"
          class="op-icon code-style-icon dropdown dropdown-wrapper"
          aria-hidden="true"
          title="代码风格"
          @mouseenter="showStyle = true"
          @mouseleave="showStyle = false"
        >
          <el-collapse-transition>
            <div
              class="op-code-style popup-dropdown transition"
              v-show="showStyle"
            >
              <div
                data-v-548e2160
                :title="style"
                class="dropdown-item"
                v-for="(style, index) in codeStyles"
                :key="index"
                @click="handleChangeStyle(index)"
              >
                <span>{{ style }}</span>
              </div>
            </div>
          </el-collapse-transition>
        </div>
        <!-- 打开文件按钮 -->
        <div
          class="op-icon el-icon-folder-opened open-file-icon"
          title="打开文件"
        >
          <input type="file" ref="file" @change="handleOpenFile" />
        </div>
        <span class="op-icon-divider"></span>
      </template>
    </mavon-editor>
    <!-- 进度条 -->
    <transition name="el-fade-in-linear">
      <el-progress
        type="circle"
        :width="64"
        :percentage="percent"
        :status="status"
        v-show="showPercent"
        class="center"
      ></el-progress>
    </transition>
    <!-- 保存 -->
    <el-row class="editor-bottom">
      <button type="button" class="x-btn x-btn-primary" @click="preserve">
        保存草稿
      </button>
      <button type="button" class="x-btn" @click="publish">发表文章</button>
    </el-row>
    <!-- 发布文章 -->
    <el-dialog
      :visible.sync="dialogVisible"
      :destroy-on-close="true"
      :show-close="false"
      :modal-append-to-body="false"
      @close="cancel"
      width="400px"
      top="15vh"
      center
    >
      <el-form label-position="right" label-width="80px">
        <el-form-item label="类型">
          <el-radio-group
            v-model="article.type"
            text-color="#5fb878"
            fill="#5fb878"
            size="small"
          >
            <el-radio :label="0">原创</el-radio>
            <el-radio :label="1">转载</el-radio>
          </el-radio-group>
          <div style="display: inline-block">
            <el-input
              v-if="article.type == 1"
              v-model="article.reprintLink"
              suffix-icon="el-icon-link"
              placeholder="请输入转载链接"
              @blur="validateLink"
            ></el-input>
          </div>
          <span v-if="errorLink" class="tip tip-error">链接格式不正确</span>
        </el-form-item>
        <el-form-item label="文章类别">
          <el-select
            v-model="category"
            filterable
            allow-create
            default-first-option
            no-data-text="空空如也~"
            placeholder="请选择文章类别"
          >
            <el-option
              v-for="cate in categories"
              :key="cate.id"
              :label="cate.name"
              :value="cate.name"
            >
            </el-option>
          </el-select>
        </el-form-item>
        <el-form-item label="文章标签">
          <el-select
            v-model="selectedtags"
            multiple
            :multiple-limit="5"
            filterable
            allow-create
            value-key="id"
            default-first-option
            no-data-text="空空如也~"
            placeholder="请选择文章标签"
          >
            <el-option
              v-for="tag in tags"
              :key="tag.id"
              :label="tag.name"
              :value="tag"
            >
            </el-option>
          </el-select>
          <span class="tip">最多只允许有5个标签</span>
        </el-form-item>
      </el-form>
      <div slot="footer">
        <button type="reset" class="x-btn x-btn-primary" @click="cancel">
          取 消
        </button>
        <button
          type="button"
          :disabled="publishBtnDisabled"
          class="x-btn"
          @click="submit"
          v-bind:class="{ 'x-btn-disabled': publishBtnDisabled }"
        >
          <i v-if="loading" class="el-icon-loading"></i>
          确 定
        </button>
      </div>
    </el-dialog>
  </div>
</template>

<script>
import { mavonEditor } from "mavon-editor"; // 引入mavon-editor，编辑器
import "mavon-editor/dist/css/index.css"; // 编辑器样式
import cryptoJS from "crypto-js";
import * as qiniu from "qiniu-js";
import request from "@/utils/request";
import { Message } from "element-ui";
import jsCookie from 'js-cookie';

export default {
  name: "Editor",
  components: {
    mavonEditor,
  },
  data() {
    return {
      // ---------------文章属性-----------------
      // 文章
      article: {},
      selectedtags: [],
      category: {
        id: null,
        name: null
      },
      // 用户的所有文章标签
      tags: [],
      // 用户的所有文章类别
      categories: [],

      // ----------------七牛云属性----------------
      // 上传文件后的根链接
      base_url: "http://img.xsirl.cn/",
      // 七牛云配置
      qnyConfig: {
        // 是否使用 cdn 加速域名
        userCdnDomain: true,
        // 选择上传域名区域；当为 null 或 undefined 时，自动分析上传域名区域。
        region: "qiniu.region.z2",
        // 上传地址
        uphost: "upload-z2.qiniup.com",
      },

      // ----------------编辑器属性------------------
      // 是否显示代码风格选项【暂不设置】
      showStyle: false,
      // 代码样式列表【暂不设置】
      codeStyles: ["github", "darcula", "monokai", "vs2015", "idea"],
      // 当前样式【暂不设置】
      currentStyle: 0,

      // ---------------页面属性-----------------
      // 是否上传显示进度
      showPercent: false,
      // 上传的进度
      percent: 0,
      // 上传的状态
      status: null,
      // 是否显示对话框
      dialogVisible: false,
      // 按钮加载中
      loading: false,
      // 按钮禁用
      publishBtnDisabled: false,
      // 错误链接
      errorLink: false,
    };
  },
  computed: {
    user() {
      return this.$store.getters.user;
    },
    qnyToken() {
      return jsCookie.get("qnyToken");
    }
  },
  watch: {
    // 监听路由变化
    // articleId存在时获取文章
    $route: {
      handler: function (to, from) {
        const articleId = to.query.articleId;
        if (articleId != null && !isNaN(articleId)) {
          this.article.id = articleId;
          this.reqeustArticle();
        } else {
          this.article = this.getDefaultArticle();
        }
      },
      immediate: true,
    },
  },
  methods: {
    getDefaultArticle() {
      return {
        id: null,
        author: "",
        authorId: "",
        authorAvatar: "",
        title: "",
        summary: "",
        content: "",
        type: 0,
        reprintLink: "",
        createTime: null,
        status: 0,
      };
    },
    reqeustArticle() {
      request.get(`/articles/${this.article.id}`).then((res) => {
        this.article = res.data.article;
        this.category = res.data.category;
        if(res.data.tags.length > 0) {
          this.selectedtags = res.data.tags.flatMap(tag => tag.name);
        }
      });
    },
    /**
     * 打开文件
     */
    handleOpenFile() {
      const _this = this;
      const file = this.$refs.file.files[0];
      const reader = new FileReader();
      reader.onload = (e) => {
        _this.article.content = e.target.result;
        // console.log(_this.article.content);
      };
      reader.readAsText(file);
    },
    /**
     * 切换代码样式
     */
    handleChangeStyle(index) {
      this.currentStyle = index;
      this.showStyle = false;
    },
    /**
     * 处理添加图片事件
     */
    handleImgAdd(pos, file) {
      let $vm = this.$refs.md;
      let _this = this;

      // 0、格式校验
      const isMage = file.type === "image/jpeg" || file.type === "image/png";
      if (!isMage) {
        this.$message({
          type: "error",
          message: "上传的图片只能是 JPG、PNG 格式!",
          duration: 1500,
        });
        return false;
      }

      // 1、压缩配置
      const options = {
        // 图片压缩质量
        quality: 0.92,
        // 若压缩后的图片比原图片大，则返回原图片
        noCompressIfLarger: true,
      };
      // 2、设置监听对象（observer为一个object，用来监听上传过程）
      const observer = {
        next(res) {
          // console.log(res);
          _this.percent = res.total.percent;
        },
        error(res) {
          console.error("图片上传失败");
          _this.status = "exception";
          // 隐藏进度
          setTimeout(() => {
            _this.showPercent = false;
          }, 200);
        },
        complete(res) {
          let url = _this.base_url + res.key;
          $vm.$img2Url(pos, url);
          _this.status = "success";
          // 隐藏进度条
          setTimeout(() => {
            _this.showPercent = false;
          }, 200);
        },
      };
      // 3、压缩图片，并上传
      qiniu.compressImage(file, options).then((res) => {
        // 3.0、显示上传进度
        _this.showPercent = true;
        // 3.1、准备上传，传入token和文件
        const observable = _this.uploadToQny(_this.qnyToken, res.dist);
        // 3.2、开始上传
        observable.subscribe(observer);
      });
    },
    /**
     * 处理编辑器保存
     */
    handleSave(value, render) {
      if (render == null || render.trim() == "") {
        return;
      }

      this.article.summary = render.replace(/<.+?>/g, "").substring(0, 100);
      // console.log(this.article.summary);
    },
    /**
     * 上传至七牛云
     */
    uploadToQny(token, file) {
      let key = this.user.name + Date.now();
      let putExtra = {
        fname: file.name,
        mimeType: file.type,
      };
      // 准备上传
      return qiniu.upload(file, key, token, putExtra, this.qnyConfig);
    },
    /**
     * 校验链接
     */
    validateLink() {
      const regex = new RegExp(/^https?:\/\//gi);
      if (!regex.test(this.article.reprintLink)) {
        this.errorLink = true;
        this.article.reprintLink = "";
      } else {
        this.errorLink = false;
      }
    },
    /**
     * 校验标题、内容
     */
    valid(value, message) {
      if (!this.isEmptyStr(value)) {
        return true;
      }
      Message({
        type: "error",
        message: message,
        duration: 1500,
        center: true,
      });
      return false;
    },
    /**
     * 保存草稿
     */
    preserve() {
      let article = this.article;
      if (
        !this.valid(article.title, "标题不能为空！") ||
        !this.valid(article.content, "内容不能为空！")
      ) {
        return;
      }

      this.beforeSubmit(() => {
        article.status = 1;
      });

      const _this = this;
      request.post("/article/preserve", article).then((res) => {
        if (res.code === 200) {
          _this.dialogVisible = false;
          _this.reset();
        }
      });
    },
    /**
     * 发布文章
     */
    publish() {
      let article = this.article;
      if (
        !this.valid(article.title, "标题不能为空！") ||
        !this.valid(article.content, "内容不能为空！")
      ) {
        return;
      }
      this.dialogVisible = true;
      this.getCategories();
      this.getTags();
    },
    /**
     * 确认发布
     */
    submit() {
      let article = this.article;
      this.beforeSubmit();
      let tags = [];
      this.selectedtags.forEach((tag) => {
        if (typeof tag === "string") {
          tag = tag.trim() == "" ? null : { name: tag };
        }
        tags.push(tag);
      });

      let obj = {
        article: article,
        category: this.category,
        tags: tags,
      };

      console.log("category => ", this.category);
      console.log("tags => ", tags);

      const _this = this;
      request.post("/articles/publish", obj).then((res) => {
        if (res.code === 200) {
          _this.dialogVisible = false;
          Message({
            type: "success",
            message: "文章已发表",
            duration: 1500,
            center: true,
            onClose: function() {
              this.$router.push("/profile/editor");
            }
          });
        }
      });
    },
    /**
     * 取消
     */
    cancel() {
      this.article.type = 0;
      this.category = "";
      this.selectedtags = [];
      this.dialogVisible = false;
    },
    /**
     * 是否为空串
     */
    isEmptyStr(str) {
      return str == null || str.trim() == "";
    },
    /**
     * 发送请求前，做些预处理
     */
    beforeSubmit(fn) {
      if (fn) {
        fn();
      }

      // 渲染后的html
      let render = this.$refs.md.markdownIt.render(this.article.content);
      this.article.summary = render.replace(/<.+?>/g, "").substring(0, 100);
      // console.log(this.article.summary);
      this.article.author = this.user.name;
      this.article.authorId = this.user.uid;
      this.article.authorAvatar = this.user.avatar;
      this.article.createTime = new Date();
    },
    /**
     * 重置所有内容
     */
    reset() {
      this.article = {};
      this.category = "";
      this.selectedtags = [];
    },
    /**
     * 获取已创建的类别
     */
    getCategories() {
      const _this = this;
      request.get("/category/author").then((res) => {
        if (res.code === 200) {
          _this.categories = res.data;
        }
      });
    },
    getTags() {
      const _this = this;
      request.get("/tag/author").then((res) => {
        if (res.code === 200) {
          _this.tags = res.data;
        }
      });
    },
  },
  created() {},
};
</script>

<style scope>
  /* 修改mavon-editor样式 */
  .v-note-img-wrapper img {
    width: 90%;
  }

  .editor-container {
    position: relative;
  }

  .editor {
    margin-top: 10px;
    height: 500px;
  }
  .editor-top {
    margin-bottom: 20px;
  }
  .editor-bottom {
    text-align: center;
    margin: 20px 0;
  }

  /* 进度条居中 */
  .center {
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    margin: auto;
    width: fit-content;
    height: fit-content;
    z-index: 9999;
  }
  /* 自定义工具栏图标 */
  .code-style-icon {
    width: fit-content !important;
  }
  .code-style-icon::before {
    content: "Code Style";
    font-weight: 600;
  }
  .popup-dropdown.op-code-style {
    min-width: 80px !important;
    left: 0 !important;
  }
  .open-file-icon {
    position: relative;
    font-size: 1em !important;
  }
  .open-file-icon input {
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    margin: auto !important;
    font-size: 0 !important;
    opacity: 0;
    cursor: pointer;
  }

  .tip-error {
    color: red !important;
  }
</style>